/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.aksw.treelearning.data;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Implements a cache that is exclusively in memory. Fastest cache as it does
 * not need to read from the hard drive.
 *
 * @author ngonga
 */
public class MemoryCache implements Cache {

    // maps uris to instance. A bit redundant as instance contain their URI
    HashMap<String, Instance> instanceMap;
    //Iterator for getting next instance
    Iterator<Instance> instanceIterator;

    public MemoryCache() {
        instanceMap = new HashMap<String, Instance>();
    }

    

    /**
     * Returns the next instance in the list of instances
     *
     * @return null if no next instance, else the next instance
     */
    public Instance getNextInstance() {
        if (instanceIterator.hasNext()) {
            return instanceIterator.next();
        } else {
            return null;
        }
    }

    /**
     * Returns all the instance contained in the cache
     *
     * @return ArrayList containing all instances
     */
    public ArrayList<Instance> getAllInstances() {
        return new ArrayList<Instance>(instanceMap.values());
    }

    public void addInstance(Instance i) {
        if (instanceMap.containsKey(i.getUri())) {
            Instance m = instanceMap.get(i.getUri());

        } else {
            instanceMap.put(i.getUri(), i);
        }
    }

    /**
     *
     * @param uri URI to look for
     * @return The instance with the URI uri if it is in the cache, else null
     */
    public Instance getInstance(String uri) {
        if (instanceMap.containsKey(uri)) {
            return instanceMap.get(uri);
        } else {
            return null;
        }
    }

    /**
     *
     * @return The size of the cache
     */
    public int size() {
        return instanceMap.size();
    }

    /**
     * Adds a new spo statement to the cache
     *
     * @param s The URI of the instance linked to o via p
     * @param p The property which links s and o
     * @param o The value of the property of p for the entity s
     */
    public void addTriple(String s, String p, String o) {
        if (instanceMap.containsKey(s)) {
            Instance m = instanceMap.get(s);
            m.addProperty(p, o);
        } else {
            Instance m = new Instance(s);
            m.addProperty(p, o);
            instanceMap.put(s, m);
        }
    }

    /**
     *
     * @param i The instance to look for
     * @return true if the URI of the instance is found in the cache
     */
    public boolean containsInstance(Instance i) {
        return instanceMap.containsKey(i.getUri());
    }

    /**
     *
     * @param uri The URI to looks for
     * @return True if an instance with the URI uri is found in the cache, else
     * false
     */
    public boolean containsUri(String uri) {
        return instanceMap.containsKey(uri);
    }

    public void resetIterator() {
        instanceIterator = instanceMap.values().iterator();
    }

    @Override
    public String toString() {
        return instanceMap.toString();
    }

    public ArrayList<String> getAllUris() {
        return new ArrayList(instanceMap.keySet());
    }

    public Cache getSample(int size) {
        Cache c = new MemoryCache();
        ArrayList<String> uris = getAllUris();
        while (c.size() < size) {
            int index = (int) Math.floor(Math.random() * size());
            Instance i = getInstance(uris.get(index));
            c.addInstance(i);
        }
        return c;
    }

    public Cache processData(String processingChain) {
        Cache c = new MemoryCache();
        for(Instance instance: getAllInstances())
        {
            String uri = instance.getUri();
            for(String p: instance.getAllProperties())
            {
                for(String value: instance.getProperty(p))
                {
                    c.addTriple(uri, p, Preprocessor.process(value, processingChain));
                }
            }
        }
        return c;
    }
    
    public static void main(String args[])
    {
        Cache c = new MemoryCache();
        c.addTriple("#1", "p", "Test@en");
        c.addTriple("#1", "p", "Test");
        c.addTriple("#2", "p", "Test21@en");
        c.addTriple("#2", "p", "Test22@en");
        c.addTriple("#2", "q", "Test23@en");
        
        c = c.processData("nolang->lowercase");
        System.out.println(c);
    }
}
